// Package verifycode 用以发送手机验证码和邮箱验证码
package verifycode

import (
	"fmt"
	"gohub/pkg/app"
	"gohub/pkg/config"
	"gohub/pkg/helpers"
	"gohub/pkg/logger"
	"gohub/pkg/mail"
	"gohub/pkg/redis"
	"strings"
	"sync"
)

type VerifyCode struct {
	Store Store
}

var once sync.Once
var internalVerifyCode *VerifyCode

// NewVerifyCode 单例模式获取
func NewVerifyCode() *VerifyCode {
	once.Do(func() {
		internalVerifyCode = &VerifyCode{
			Store: &RedisStore{
				RedisClient: redis.Redis,
				// 增加前缀保持数据库整洁，出问题调试时也方便
				KeyPrefix: config.GetString("app.name") + ":verifycode:",
			},
		}
	})

	return internalVerifyCode
}

// SendEmail 发送邮件验证码，调用示例：
//
//	verifycode.NewVerifyCode().SendEmail(request.Email)
func (vc *VerifyCode) SendEmail(email string) error {

	// 生成验证码
	code := vc.generateVerifyCode(email)

	// 方便本地和 API 自动测试
	if !app.IsProduction() && strings.HasSuffix(email, config.GetString("verifycode.debug_email_suffix")) {
		return nil
	}

	content := fmt.Sprintf("<h1>您的 Email 验证码是 %v </h1>", code)
	// 发送邮件
	mail.NewMailer().Send(mail.Email{
		From: mail.From{
			Address: config.GetString("mail.from.address"),
			Name:    config.GetString("mail.from.name"),
		},
		To:      []string{email},
		Subject: "Email 验证码",
		HTML:    []byte(content),
	})

	return nil
}

// 发送短信验证码
//
//	verifycode.NewVerifyCode().SendEmail(request.Email)
func (vc *VerifyCode) SendCode(phone string) string {
	// 生成验证码
	code := vc.generateVerifyCode(phone)
	// params := make(map[string]interface{})

	// //请登录zz.253.com获取API账号、密码以及短信发送的URL
	// params["account"] = "N328752_N0865902" //创蓝API账号
	// params["password"] = "7idExRkgQ1a285"  //创蓝API密码
	// params["phone"] = phone                //手机号码

	// //设置您要发送的内容：其中“【】”中括号为运营商签名符号，多签名内容前置添加提交
	// content := fmt.Sprintf("【太能塔】您好，您的验证码是%v", code)
	// params["msg"] = url.QueryEscape(content)
	// params["report"] = "true"
	// bytesData, err := json.Marshal(params)
	// if err != nil {
	// 	fmt.Println(111)
	// 	return err
	// }
	// reader := bytes.NewReader(bytesData)
	// url := "http://smssh1.253.com/msg/send/json" //短信发送URL
	// request, err := http.NewRequest("POST", url, reader)
	// if err != nil {
	// 	return err
	// }
	// request.Header.Set("Content-Type", "application/json;charset=UTF-8")
	// client := http.Client{}
	// resp, err := client.Do(request)
	// if err != nil {
	// 	return err
	// }
	// respBytes, err := io.ReadAll(resp.Body)
	// if err != nil {
	// 	return err
	// }
	// strs := fmt.Sprintf("%s", respBytes)
	// data := []byte(strs)
	// var result map[string]interface{}
	// errs := json.Unmarshal(data, &result)
	// if errs != nil {
	// 	return errs
	// }

	// if result["code"] != 0 {
	// 	errorMsg := fmt.Sprint(result["errorMsg"])
	// 	return errors.New(errorMsg)
	// }
	return code
	// str := (*string)(unsafe.Pointer(&respBytes))
	// strs := *str

	// 方便本地和 API 自动测试
	// if !app.IsProduction() && strings.HasSuffix(phone, config.GetString("verifycode.debug_phone_suffix")) {
	// 	return nil
	// }
	// params := make(map[string]string)
	// params["account"] = "N328752_N0865902" //创蓝API账号
	// params["password"] = "7idExRkgQ1a285"  //创蓝API密码
	// content := fmt.Sprintf("您正在注册%v会员，验证码%v请于10分钟内使用，工作人员不会向您索取，请勿泄漏。", phone, code)
	// //设置您要发送的内容：其中“【】”中括号为运营商签名符号，多签名内容前置添加提交

	// params["msg"] = url.QueryEscape(content)
	// params["report"] = "true"
	// fmt.Println(params)
	// bytesData, err := json.Marshal(params)
	// if err != nil {
	// 	return err
	// }
	// reader := bytes.NewReader(bytesData)
	// url := "https://smssh1.253.com/msg/variable/json" //短信发送URL
	// request, errs := http.NewRequest("POST", url, reader)
	// fmt.Println(request)
	// return errs
}

// CheckAnswer 检查用户提交的验证码是否正确，key 可以是手机号或者 Email
func (vc *VerifyCode) CheckAnswer(key string, answer string) bool {

	logger.DebugJSON("验证码", "检查验证码", map[string]string{key: answer})

	// 方便开发，在非生产环境下，具备特殊前缀的手机号和 Email后缀，会直接验证成功
	if !app.IsProduction() &&
		(strings.HasSuffix(key, config.GetString("verifycode.debug_email_suffix")) ||
			strings.HasPrefix(key, config.GetString("verifycode.debug_phone_prefix"))) {
		return true
	}

	return vc.Store.Verify(key, answer, false)
}

// generateVerifyCode 生成验证码，并放置于 Redis 中
func (vc *VerifyCode) generateVerifyCode(key string) string {

	// 生成随机码
	code := helpers.RandomNumber(config.GetInt("verifycode.code_length"))

	// 为方便开发，本地环境使用固定验证码
	// if app.IsLocal() {
	// 	code = config.GetString("verifycode.debug_code")
	// }

	logger.DebugJSON("验证码", "生成验证码", map[string]string{key: code})

	// 将验证码及 KEY（邮箱或手机号）存放到 Redis 中并设置过期时间
	vc.Store.Set(key, code)
	return code
}
